`timescale 1ns/1ps

module tb_test(
	);
	
//initial 语句的使用
reg init_rst_n;

initial begin
    #0;
    init_rst_n = 1'b1;
    #2;
    init_rst_n = ~init_rst_n;
    #4;     //4个单位时间保持复位
    init_rst_n = ~init_rst_n;
end

//forever 语句的使用
parameter ClkPeriod = 10;
reg clk;
initial begin
    #0 clk = 1'b0;
	forever
    begin
        #(ClkPeriod/2) clk = ~clk;
    end
    
end

//always 产生时钟
parameter ClkPeriod1 = 5.0;
reg clk1;
initial #0 clk1 = 1'b1;
always#(ClkPeriod1/2)
begin
    clk1 = ~clk1;
end

//repeat 产生脉冲
reg pulse1;
initial
begin
	#0 pulse1 = 1'b0;
    repeat(6) #(1) pulse1 = ~pulse1;
end

//forever 非对称时钟
reg clk2;
initial begin
	clk2 = 1'b1;
    forever begin
       #((ClkPeriod/2)-2) clk2 = 1'b0 ;
       #((ClkPeriod/2)+2) clk2 = 1'b1 ;       
    end
end

//同步复位信号
reg rst_p;
initial begin
	#0 rst_p = 1'b0;
    @(posedge clk1) rst_p = 1'b1;
    repeat(3) @(posedge clk1);      //3个上升沿后 复位信号无效
    @(posedge clk1) rst_p = 1'b0;
end

//task 产生复位信号
task reset_task;
    input[31:0] reset_time;     //复位时长可调
    inout reset_signal;        //复位信号输出
    
    reg RST_Level;          //复位电平
    begin
        RST_Level = reset_signal;
        #reset_time;
        reset_signal = ~RST_Level;
    end
endtask

reg rst_task_s;
initial begin
    rst_task_s = 1'b1;  // task 内部未消耗完仿真时间前，不会刷新输出，所以要复位  
	reset_task(11,rst_task_s);
end


//wait 语句的使用
reg en;
initial begin
	#0 en = 1'b0;
    #5;
    wait(init_rst_n == 1'b1);
    en = 1'b1;
end

/*
----------------------------------------------------------------
仿真控制语句及系统任务描述
---------------------------------------------------------------- ---------------------------------------------------------------- 
$random //产生随机数
$random % n //产生范围 -n到 n之间的随机数
{$random} % n //产生范围 0到 n之

$stop //停止运行仿真， modelsim中可继续仿真 中可继续仿真
$stop(n) //带参数 系统任务，根据0,1或 2不同，输出仿真信息
$finish //结束运行仿真，不可继续

$finish(n) //带参数 系统任务，根据0,1或 2不同，输出仿真信息 不同，输出仿真信息
    //0:不输出任何信息
    //1:输出当前仿真时刻和位置
    //2:输出当前仿真时刻、位置和过程中用到的 输出当前仿真时刻、位置和过程中用到的 memory以及 CPU时间的统计
*/

reg msignal;
initial begin
    $monitor($time,,,"monitor msignal=%d",msignal);   //monitor是在信号发生变化时打印
    msignal = 1'b0;
    #2;
    msignal = 1'b1;
    $display("msignal=%d",msignal); //display是立即打印
    #2;
    msignal = 1'b0;
    $display("display msignal=%d",msignal); //display是立即打印   这里打印为0
    $strobe("strobe msignal=%d",msignal); //strobe一般用于非阻塞赋值的显示  这里打印为1
    msignal = 1'b1;
    #2;
    msignal = 1'b1;
end

always@(posedge pulse1 ) begin
	$strobe("strobe1 msignal=%d",msignal); //strobe一般用于非阻塞赋值的显示 这里非阻塞执行完才打印
end

/*
一些读入文件数据的相关宏指令
$readmemb/$readmemh("<数据文件名 数据文件名 >",<存储器名 >);
$readmemb/$readmemh("<数据文件名 数据文件名 >",<存储器名 >,<起始地址 起始地址 >);
$readmemb/$readmemh("<数据文件名 数据文件名 >",<存储器名 >,<起始地址 起始地址 >,<结束地址 >);
$readmemb: 
          读取二进制数 据，文件内容只能包含：空白位置注释行读取二进制数
          据，文件内容只能包含：空白位置注释行数据中不能包含位宽说明和格式，每个字必须是二进制。 
$readmemh:
            读取十六进制数 据，文件内容只能包含：空白位置注释行读取十六进制数
            据，文件内容只能包含：空白位置注释行数据中不能包含位宽说明和格式，每个字必须是十六进制。 
            当地址出现在数据文件中，格式为 当地址出现在数据文件中，格式为 @hh...h,地址与数字之间不允许空白位置， 地址与数字之间不允许空白位置，
            可出现多个地址 
*/

//读取文件数据
reg [7:0] memory[0:3];  //声明三个字节的储存器
integer i;
initial begin
	$readmemh("mem.dat",memory);    //从mem.dat读取数据到 memory
    //显示读取到的内容
    for(i=0;i<4;i=i+1) begin
        $display("memory[%d]=%04h",i,memory[i]);
    end
    
end


endmodule

